package com.zzj.ecology.framework.configuration.security;

import com.zzj.ecology.system.bean.system.SysPermission;
import com.zzj.ecology.system.bean.system.SysRole;
import com.zzj.ecology.system.bean.system.SysUrl;
import com.zzj.ecology.system.bean.system.SysUrlExample;
import com.zzj.ecology.system.mapper.system.SysRoleMapper;
import com.zzj.ecology.system.mapper.system.SysUrlMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Component
public class CustomizeFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    @Autowired
    private SysUrlMapper sysUrlMapper;
    @Autowired
    private SysRoleMapper sysRoleMapper;

    /**
     * 用于保存角色表中的所有角色权限
     */
    private HashMap<String, Collection<ConfigAttribute>> map;

    /**
     * 加载资源 角色表中所有的角色信息
     */
    public void loadResourceDefine() {
        map = new HashMap<>();
        List<SysPermission> sysPermissions = null;
        List<SysRole> sysRoles = null;

        // 查询出所有 URL
        SysUrlExample urlExample = new SysUrlExample();
        List<SysUrl> urls = sysUrlMapper.selectByExample(urlExample);

        Collection<ConfigAttribute> configAttributes = null;
        ConfigAttribute configAttribute = null;

        for (SysUrl url : urls) {
            Integer urlId = url.getUrlId();//
            sysRoles = sysRoleMapper.findRolesByUrlId(urlId);//每个 URL 对应的 ROLE 权限集合
            configAttributes = new ArrayList<ConfigAttribute>();// 封装一个URL地址对应的Permission权限集合
            for (SysRole sysRole : sysRoles) {
                /*
                 * 此处只添加了权限的英文代号,还可以添加更多权限的信息,
                 * 例如请求方法到ConfigAttribute的集合中去。
                 * 此处添加的信息将会作为 com.zeng.boot.web.security.CustomAccessDecisionManager 类的 decide 的第三个参数。
                 * */
                configAttribute = new SecurityConfig(sysRole.getRoleCode());//英文代号 作权限 标识
                configAttributes.add(configAttribute);
                // key 是 URL地址，用ConfigAttribute的集合作为 value
                map.put(url.getUrlPath(), configAttributes);
            }
        }

    }

    /**
     * 此方法是为了判定用户请求的url是否在权限表中,
     * 如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。
     * 如果不在权限表中则放行。
     * */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        if (map == null) loadResourceDefine();
        /*
         * getAttributes(Object object)中的Object包含用户请求的request信息
         * */
        HttpServletRequest httpRequest = ((FilterInvocation) object).getHttpRequest();

        String resUrl = null;
        AntPathRequestMatcher matcher = null;

        Iterator<String> iters = map.keySet().iterator();
        while (iters.hasNext()) {
            resUrl = iters.next();
            matcher = new AntPathRequestMatcher(resUrl);
            if (matcher.matches(httpRequest)) {//于当前的请求路径相吻合, 返回给 decide 方法
                Collection<ConfigAttribute> configAttributes = map.get(resUrl);
                return configAttributes;// 返回一个URL地址对应的所有 Role 权限 (英文代号)
            }
        }
        // return null ,不用进入 CustomizeAccessDecisionManager.java 中判断权限
        return null;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}
